Repository navigation
Conversation
An app with a theme of its own needs the system tab bar's selected tab in its colors, as `NavPage`'s `headerStyle` already allows with `tintColor`. The core already hands `tint-*` to the bar's native view; this test holds it there for the platforms to color the selected tab with, and the compat case uses `tint-foreground` on the bar. Today both platforms ignore it: on an iOS 26 simulator a bar with `tint-[#ff2d55]` still shows its selected tab in the system blue (#367ced in a screenshot).
`nsh/mobile`'s `TabBar` showed its selected tab in the system accent (blue on iOS), whatever the app's theme: an app in black and white could not make the bar match its own header, which takes `tintColor` through `headerStyle`. The bar now takes the `tintColor` of its style (`tint-<color>`, Rust `.tint_color(..)`) for the selected tab; the other tabs and the bar itself keep the system's look. iOS: a native component's container carries the style's tint as UIKit's `tintColor`, which the `UITabBar` inside inherits, as UIKit views do. Android: the component's box hands the tint to the Material 3 bar, which draws the selected icon and label in it over an active indicator of it at 12% opacity (Material's state-layer opacity).
| } | ||
| if (v instanceof ImageBox) ((ImageBox) v).setTint(hasTint ? tint : 0); | ||
| else if (v instanceof ComponentBox) ((ComponentBox) v).setTint(hasTint ? tint : 0); | ||
| applyDynamic(v, d); |
There was a problem hiding this comment.
[P3] Preserve whether a tint was explicitly supplied. 0 is also a valid transparent color, so tint-transparent currently restores the system-selected color on Android instead of making it transparent. Pass hasTint separately (or use a nullable color) through ComponentBox and cover explicit transparent tint versus removing the tint.
Reviewed by ChatGPT on behalf of @huacnlee.
There was a problem hiding this comment.
Fixed in 813d0a1. The tint now travels as a nullable Integer through ComponentBox and TabBarComponent: tint-transparent is a color, no tint is null. The indicator takes 12% of the tint's own alpha, so a transparent tint draws none.
a_transparent_tint_reaches_the_tab_bar_as_a_colorchecks the core sendstint-transparentasColor(0), not as no tint.- Android 15 emulator, read from the screenshots: before the fix,
tint-transparentdrew the system's #414659 indicator and #E3E2E9 label, the same as no tint. After it, neither shows; without a tint the tab is #414659 / #E3E2E9 as before.
ImageBox keeps its own 0-means-none, which this PR doesn't touch.
ComponentBox and TabBarComponent took 0 for "no tint", so tint-transparent gave the selected tab the system's colors. The tint now travels as a nullable color: transparent is a color, null the system's. The indicator keeps 12% of the tint's own alpha, so a transparent tint draws none.
|
The tintColor is not cover the all platforms, please remove and use existing primary color instead |
`tint-*` is not a style every platform takes, so the bar no longer reads it. The core's `TabBar` sends the theme's `primary`, for the appearance shown, as the bar's `tint` prop; iOS sets it as the `UITabBar`'s `tintColor`, Android draws the selected icon and label in it over an indicator of it at 12% opacity. The style plumbing for a component's tint and its docs are gone.
|
Done in 53d93b4: One choice left for you: an app without its own theme now gets the default |
Description
An app with its own palette colors its buttons and its stack header, but the tab bar under them keeps the system accent: blue on iOS, the wallpaper's color on Android. In a black-and-white app it is the one blue thing on screen.
The selected tab now takes the theme's
primary, the color the app's buttons already use. There is nothing to set: an app with a theme innsh.jsongets it, and a theme set while the app runs (set_tokens) reaches the bar too. The other tabs, the bar's material and its height stay the system's.How the color reaches the screen:
TabBarreadsprimaryfromtokens()for the appearance shown and sends it as the bar'stintprop (#RRGGBB). Reading the tokens and the appearance subscribes, so a new theme or a switch to dark sends it again.UITabBar'stintColor, in which UIKit draws the selected item.TabBarComponentdraws the selected icon and label in it, over the active indicator in the same color at 12% opacity (Material's state-layer opacity).The first version of this PR read
tint-*from the bar's style. Following review, it readsprimaryinstead, and the style plumbing it had added (ComponentBox, the iOS component container, the docs oftint-*) is gone.Screenshots
A theme with
primary#FF2D55 (light) and #0A84FF (dark), and an app with no theme of its own:Read from the pixels, on both platforms: the selected label is #FF2D55 in light and #0A84FF in dark with the theme, #171717 and #E5E5E5 (
nsh-base's defaultprimary) without one. On iOS, switching the simulator to dark while the app runs turns it from #FF2D55 to #0A84FF. (The Android icons are blank because the test app names SF Symbols.)Public API
None.
TabBarhas no new prop; its native component getstintfrom the core.Breaking Changes
Every
TabBar's selected tab changes color. An app without a theme of its own now gets the defaultprimary(near black in light, near white in dark) where it had system blue on iOS and the wallpaper's accent on Android. On iOS 26 that near black is also the other tabs' color, so the glass pill alone shows the selection (row "No theme, light").If apps without a theme should keep the system accent, the core can send no
tintwhile the tokens are the default theme's; #742 does that for dialogs. Say which you prefer and I'll make it so.How to Test
cargo test -p nsh-engine --test engine tab_bar:the_tab_bar_takes_the_themes_primary_colorchecks thetintprop on iOS and Android, in light and then in dark.cargo test -p nsh-platform-ios --target aarch64-apple-ios-macabi --lib tint: the iOS bar reads the prop's hex.nsh.jsontheme setsprimary, with a<TabBar>and no class:nsh run App.tsx --target iosand--target android, in light and dark mode.Ran:
cargo test --workspace(passes),cargo clippy --all-targets -p nsh-core -p nsh-engine -- -D warnings, the Catalyst clippy,cargo xtask clippy-android(all clean),cargo xtask android --release --dev --abi arm64-v8a,rustfmt +nightly --checkon the changed Rust files.Checklist
cargo test --workspace,cargo +nightly fmt --alland clippy (including the Catalyst and Android runs for platform code).tests/compat/(cargo xtask compat): no API change, so no case.examples/gallerydemos on iOS and Android (if the change is visible or platform-specific).